package com.dlc.shop.search.multishop.controller;

import cn.hutool.core.collection.CollectionUtil;
import com.dlc.shop.bean.enums.ProdType;
import com.dlc.shop.bean.event.EsProductActivityInfoEvent;
import com.dlc.shop.bean.param.EsProductParam;
import com.dlc.shop.bean.vo.SkuStockVO;
import com.dlc.shop.bean.vo.search.ProductSearchVO;
import com.dlc.shop.common.constants.CacheNames;
import com.dlc.shop.common.constants.EsCacheNames;
import com.dlc.shop.common.enums.EsRenovationProductSortEnum;
import com.dlc.shop.common.response.ServerResponseEntity;
import com.dlc.shop.common.util.EsPageVO;
import com.dlc.shop.common.util.RedisUtil;
import com.dlc.shop.search.common.constant.EsConstant;
import com.dlc.shop.search.common.manager.ProductSearchManager;
import com.dlc.shop.search.common.param.EsPageParam;
import com.dlc.shop.search.common.service.SearchProductService;
import com.dlc.shop.security.multishop.util.SecurityUtils;
import com.dlc.shop.service.SkuService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import lombok.AllArgsConstructor;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.*;

/**
 * @author lgh
 */
@RestController
@RequestMapping("/admin/search/prod")
@Tag(name = "商家端商品搜索接口")
@AllArgsConstructor
public class EsProductController {

    private final SearchProductService searchProductService;
    private final ProductSearchManager productSearchManager;
    private final ApplicationEventPublisher eventPublisher;
    private final SkuService skuService;

    @GetMapping("/page")
    @Operation(summary = "商品信息列表", description = "商品信息列表")
    public ServerResponseEntity<EsPageVO<ProductSearchVO>> page(@Valid EsPageParam pageParam, EsProductParam productParam) {
        Long shopId = SecurityUtils.getShopUser().getShopId();
        productParam.setShopId(shopId);
        productParam.setFetchSource(EsConstant.SHOP_FETCH_SOURCE);
        EsPageVO<ProductSearchVO> searchPage = searchProductService.adminPage(pageParam, productParam);
        handleProdStock(searchPage);
        return ServerResponseEntity.success(searchPage);
    }


    @GetMapping("/renovationPage")
    @Operation(summary = "商品信息列表(装修商品列表)", description = "商品信息列表(装修商品列表)")
    @PreAuthorize("@pms.hasPermission('admin:searchProd:renovationPage')")
    public ServerResponseEntity<EsPageVO<ProductSearchVO>> renovationPage(@Valid EsPageParam pageParam, EsProductParam productParam) {
        productParam.setShopId(SecurityUtils.getShopUser().getShopId());
        Long size = null;
        if (Objects.equals(productParam.getShowSpuType(), 1)) {
            if (Objects.equals(productParam.getEsRenovationSpuSort(), EsRenovationProductSortEnum.CREATE_TIME_ASC.value()) || Objects.equals(productParam.getEsRenovationSpuSort(), EsRenovationProductSortEnum.CREATE_TIME_DESC.value())) {
                productParam.setSort(productParam.getEsRenovationSpuSort());
            } else {
                // 获取指定规则的商品ids
                size = getSpuIds(pageParam, productParam);
                pageParam.setCurrent(1);
            }
        }
        EsPageVO<ProductSearchVO> searchPage = searchProductService.renovationPage(pageParam, productParam, size);
        if (CollectionUtil.isEmpty(searchPage.getRecords())) {
            return ServerResponseEntity.success(searchPage);
        }
        // 如果包含秒杀、团购活动商品，就插入活动信息
        long count = searchPage.getRecords().stream().filter(product -> Objects.equals(product.getProdType(), ProdType.PROD_TYPE_GROUP.value()) || Objects.equals(product.getProdType(), ProdType.PROD_TYPE_SECKILL.value())).count();
        if (count > 0) {
            eventPublisher.publishEvent(new EsProductActivityInfoEvent(searchPage.getRecords()));
        }
        return ServerResponseEntity.success(searchPage);
    }

    @GetMapping("/prodExport")
    @Operation(summary = "商品导出", description = "商品导出")
    @PreAuthorize("@pms.hasPermission('prod:prod:exportProd')")
    public void prodExport(HttpServletResponse response, EsProductParam productParam) {
        productParam.setShopId(SecurityUtils.getShopUser().getShopId());
        searchProductService.export(response, productParam);
    }

    @SuppressWarnings("unchecked")
    private Long getSpuIds(EsPageParam pageParam, EsProductParam productParam) {
        Long shopId = Objects.isNull(productParam.getShopId()) ? 0L : productParam.getShopId();
        String key = EsCacheNames.RENOVATION_PRODUCT_IDS_CACHE + CacheNames.UNION + shopId +
                CacheNames.UNION_KEY + productParam.getEsTimeRange() + CacheNames.UNION_KEY + productParam.getEsRenovationSpuSort()
                + CacheNames.UNION_KEY + (Objects.isNull(productParam.getPrimaryCategoryId()) ? 0 : productParam.getPrimaryCategoryId());
        if (!RedisUtil.hasKey(key)) {
            productSearchManager.addRenovationSpuCache(key, productParam, shopId, EsCacheNames.RENOVATION_PRODUCT_IDS_CACHE_TIME);
        }
        Long size = RedisUtil.getListSize(key);
        long startNum = (long) (pageParam.getCurrent() - 1) * pageParam.getSize();
        long endNum = (long) pageParam.getCurrent() * pageParam.getSize() - 1;
        endNum = Math.min(endNum, size);
        List<Long> prodIds = RedisUtil.getListRange(key, startNum, endNum);
        productParam.setProdIds(prodIds);
        return size;
    }

    private void handleProdStock(EsPageVO<ProductSearchVO> searchPage) {
        List<Long> prodIds = searchPage.getRecords().stream().map(ProductSearchVO::getProdId).toList();
        if (prodIds.size() == 0) {
            return;
        }
        Map<Long, SkuStockVO> prodStockMap = skuService.mapProdStock(prodIds);
        for (ProductSearchVO productSearchVO : searchPage.getRecords()) {
            SkuStockVO skuStockVO = prodStockMap.get(productSearchVO.getProdId());
            productSearchVO.setTotalStocks(skuStockVO.getStock());
        }
    }
}
